package xyz.xtt.third.service.impl;

import static xyz.xtt.common.asset.AssertUtils.nonNull;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;

import cn.hutool.core.lang.Pair;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.client.request.ThirdOrderRequest;
import xyz.xtt.asset.client.response.AssetAllInfoResponse;
import xyz.xtt.asset.client.response.AssetExtInfoResponse;
import xyz.xtt.asset.client.response.MintResponse;
import xyz.xtt.common.asset.AssertUtils;
import xyz.xtt.common.starter.cache.CacheManager;
import xyz.xtt.third.constants.ErrorMessage;
import xyz.xtt.third.constants.ThirdCache;
import xyz.xtt.third.entity.TblThirdOrder;
import xyz.xtt.third.enums.ThirdOrderTypeEnum;
import xyz.xtt.third.enums.UserType;
import xyz.xtt.third.request.RoseOrderParam;
import xyz.xtt.third.request.RoseOrderRequest;
import xyz.xtt.third.service.IInnserService;
import xyz.xtt.third.service.IRoseService;
import xyz.xtt.third.service.ITblThirdOrderService;
import xyz.xtt.third.utils.RSAUtil;
import xyz.xtt.user.client.request.UserRegRequest;
import xyz.xtt.user.client.response.UserInfoResponse;
import xyz.xtt.user.client.response.UserRegResponse;

/**
 * @author huqibo
 * @date 2025/02/10
 */
@Slf4j
@RefreshScope
@Service
public class IRoseServiceImpl implements IRoseService {
	@Autowired
	private CacheManager cacheManager;

	@Value("${asset.rose.configId:1000}")
	private String[] roseConfigId;

	@Value("${asset.rose.sercret}")
	private String roseSercret;

	@Value("${asset.rose.publicKey}")
	private String rosePublicKey;

	@Value("${asset.rose.privateKey}")
	private String rosePrivateKey;

	@Value("${rocketmq.consumer.third.rose.order}")
	private String roseThirdTopic;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private ITblThirdOrderService iTblThirdOrderService;
	@Autowired
	private RocketMQTemplate rocketMQTemplate;
	@Autowired
	private IInnserService iInnserService;

	@SuppressWarnings("unchecked")
	private RoseOrderParam thirdOrderBeforeCheck(String data) {
		AssertUtils.isTrue(StringUtils.isBlank(data), ErrorMessage.THIRD_RECEIVE_ISBLANK);
		RSA rsa = new RSA(rosePrivateKey, rosePublicKey);
		byte[] decrypt = rsa.decrypt(data, KeyType.PrivateKey);
		String jsonStr = StrUtil.str(decrypt, StandardCharsets.UTF_8);
		RoseOrderParam param = JSONUtil.toBean(jsonStr, RoseOrderParam.class);
		AssertUtils.isNull(param, ErrorMessage.THIRD_PARAM_ISNULL);
		log.info("RoseOrderParam param:{}", JSONUtil.toJsonStr(param));
		AssertUtils.isFalse(StringUtils.length(param.getPhonenumber()) == 11, ErrorMessage.THIRD_ORDER_PHONR_EX);
		boolean isValid = Validator.isMobile(param.getPhonenumber());
		AssertUtils.isFalse(isValid, ErrorMessage.THIRD_ORDER_PHONR_EX);
		Map<String, Object> bizParams = JSONUtil.toBean(jsonStr, Map.class);
		bizParams.remove("sign");
		String generateSign = RSAUtil.generateSign(roseSercret, bizParams);
		// 校验签名
		AssertUtils.isFalse(Objects.equals(generateSign, param.getSign()), ErrorMessage.THIRD_ORDER_SIGN_EX);
		boolean anyMatch = Arrays.stream(roseConfigId).anyMatch(x -> StringUtils.equals(param.getConfigId(), x));
		AssertUtils.isFalse(anyMatch, ErrorMessage.THIRD_ORDER_CONFIG_EX);
		AssetAllInfoResponse info = iInnserService.infoGoodsId(param.getConfigId());
		AssertUtils.isNull(info, ErrorMessage.ASSET_NOT_EXIST);
		AssetExtInfoResponse assetExt = info.getAssetExt();
		AssertUtils.isNull(assetExt, ErrorMessage.ASSET_NOT_EXIST);
		AssertUtils.isFalse(assetExt.checkTime(), ErrorMessage.ASSERT_SELL_DATE_PERIOD);
		TblThirdOrder dbOrder = iTblThirdOrderService.infoCahceWithOrderNumer(param.getOrderNumber());
		AssertUtils.nonNull(dbOrder, ErrorMessage.THIRD_ORDER_EXIST);
		return param;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Boolean thirdOrderMsgAfter(TblThirdOrder order) {
		String orderNumber = order.getOrderNumber();
		TblThirdOrder dbOrder = iTblThirdOrderService.infoCahceWithOrderNumer(orderNumber);
		if (Objects.isNull(dbOrder)) {
			log.info("thirdOrderMsgAfter is null:{}", JSONUtil.toJsonStr(order));
			return Boolean.FALSE;
		}
		Integer result = dbOrder.getResult();
		if (Objects.equals(result, 1)) {
			log.info("thirdOrderMsgAfter received:{}", JSONUtil.toJsonStr(order));
			return Boolean.FALSE;
		}
		Pair<UserType, Long> user = userInfo(dbOrder.getPhonenumber(), dbOrder.getUserName());
		Long uid = user.getValue();
		ThirdOrderRequest thirdOrder = ThirdOrderRequest.builder().appUserId(user.getValue()).configId(dbOrder.getConfigId()).build();
		MintResponse rosePayAfter = iInnserService.thirdOrder(thirdOrder);
		AssertUtils.isNull(rosePayAfter, ErrorMessage.THIRD_ORDER_MSG_EX);
		Boolean updateResult = iTblThirdOrderService.updateResult(orderNumber, uid, 1, rosePayAfter.getTransactionOrderId());
		AssertUtils.isFalse(updateResult, ErrorMessage.THIRD_ORDER_SAVE_EX);
		return Objects.nonNull(rosePayAfter);
	}

	private Pair<UserType, Long> userInfo(String mobile, String nickName) {
		UserInfoResponse infoWithPhone = iInnserService.infoWithPhone(mobile);
		if (Objects.nonNull(infoWithPhone)) {
			return new Pair<UserType, Long>(UserType.OLD_USER, infoWithPhone.getAppUserId());
		}
		UserRegRequest userRegRequest = UserRegRequest.builder().phone(mobile).name(nickName).build();
		UserRegResponse register = iInnserService.register(userRegRequest);
		nonNull(register, ErrorMessage.USER_REG_EX);
		return new Pair<UserType, Long>(UserType.NEW_REG, register.getAppUid());
	}

	@Override
	public Boolean after(String orderNumber) {
		TblThirdOrder order = iTblThirdOrderService.infoWithOrderNumer(orderNumber);
		AssertUtils.isNull(order, ErrorMessage.THIRD_ORDER_SAVE_EX);
		String jsonString = JSONUtil.toJsonStr(order);
		String message = JSON.toJSONString(order);
		String topic = String.format("%s:%s", roseThirdTopic, ThirdOrderTypeEnum.ROSE.name());
		rocketMQTemplate.convertAndSend(topic, message);
		return Objects.nonNull(order);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean thirdOrder(RoseOrderRequest roseOrder) {
		RoseOrderParam param = thirdOrderBeforeCheck(roseOrder.getData());
		return roseOrder(param);
	}

	@Override
	public Boolean roseOrder(RoseOrderParam param) {
		TblThirdOrder order = TblThirdOrder
				.builder()
				.id(IdUtil.getSnowflakeNextId())
				.phonenumber(param.getPhonenumber())
				.userName(param.getUserName())
				.configId(param.getConfigId())
				.orderNumber(param.getOrderNumber())
				.totalAmount(param.getTotalAmount())
				.bizType(ThirdOrderTypeEnum.ROSE.name())
				.userId(0L)
				.userType(0)
				.result(0)
				.crt(LocalDateTime.now())
				.build();
		boolean save = iTblThirdOrderService.save(order);
		AssertUtils.isFalse(save, ErrorMessage.THIRD_ORDER_SAVE_EX);
		String jsonString = JSONUtil.toJsonStr(order);
		ThirdCache tblThirdOrder = ThirdCache.TBL_THIRD_ORDER;
		stringRedisTemplate.opsForValue().set(tblThirdOrder.genKey(order.getOrderNumber()), jsonString, tblThirdOrder.ttl(), tblThirdOrder.timeUnit());
		String message = JSON.toJSONString(order);
		String topic = String.format("%s:%s", roseThirdTopic, ThirdOrderTypeEnum.ROSE.name());
		rocketMQTemplate.convertAndSend(topic, message);
		log.info("thirdOrder sendMessage topic:{},message:{}", topic, message);
		return Boolean.TRUE;
	}

}
